package inutan.common.manager;

import bright.serialization.AbstractBean;
import bright.serialization.ByteBuf;
import inutan.common.entity.GatewayServerInfo;
import inutan.common.inner.protocol.InnerProtocol;
import inutan.common.utils.RedisKeys;
import inutan.common.utils.RedisUtils;
import org.ricks.common.exception.ServerBootstrapException;
import org.ricks.common.json.JSONObject;
import org.ricks.common.lang.Assert;
import org.ricks.common.utils.TimeUtils;
import org.ricks.net.AioClient;
import org.ricks.net.AioSession;
import org.ricks.net.ReconnectPlugin;
import org.ricks.net.handler.MessageProcessor;
import org.ricks.net.handler.Protocol;
import org.ricks.orm.OrmContext;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 网关管理器
 * 1.传统模式 zk
 * 2.io-game 无中心化集群 gossip
 * 3.游戏后台管理 维护网关节点列表，网关节点增加 随机获取存活得一个网关节点 由此网关节点通知 所有逻辑模块节点 。
 * 逻辑节点 增加重连机制，如果网关节点重启 定时重连
 * 网关节点删除，随机获取存活得一个网关节点 由此网关节点通知 所有逻辑模块节点。逻辑节点移除重连机制
 * 逻辑节点启动，需要load 所有存活的网关节点信息 conncect   redis or mysql
 */
public class GatewayManager {

    private final List<AioSession> gatewayList = new ArrayList<>();

    public static GatewayManager me() {
        return Holder.ME;
    }

    /** 通过 JVM 的类加载机制, 保证只加载一次 (singleton) */
    private static class Holder {
        static final GatewayManager ME = new GatewayManager();
    }

    private GatewayManager() {}

    /**
     *  redis 方案
     *
     *          Map<String,String> activeBrokers =  RedisUtils.hgetAll(RedisKeys.BROKER_MANAGER_LIST);
     *         Assert.isTrue(!activeBrokers.isEmpty(),"警告：未发现存活的网关节点，请启动网关节点 ！ ");
     *         for (Map.Entry<String,String> entry: activeBrokers.entrySet()) {
     *             JSONObject jsonObject = new JSONObject(entry.getValue());
     *             BrokerMessage brokerMessage = jsonObject.toBean(BrokerMessage.class);
     *             createSession(brokerMessage);
     *         }
     */
    public void start(Protocol protocol, MessageProcessor processor){
//        var survivalGatewayList = OrmContext.me().loadAll(GatewayServerInfo.class).stream()
//                .filter(gateInfo -> gateInfo.getFlushTime() + 15_000 > TimeUtils.now())
//                .toList();
//        Assert.isTrue(!survivalGatewayList.isEmpty(),"警告：未发现存活的网关节点，请启动网关节点 ！ ");
//        survivalGatewayList.forEach(gatewayServerInfo -> {
//            String gatewayInnerAddress = gatewayServerInfo.getInnerAddress();
//            gatewayList.add(connect(gatewayInnerAddress, protocol, processor));
//        });
//        ReconnectPlugin.get().run();
    }

    public AioSession connect(String localAddress, Protocol protocol, MessageProcessor processor) {
        String[] localAddressInfo = localAddress.split(":");
        return connect(localAddressInfo[0], Integer.valueOf(localAddressInfo[1]), protocol, processor);
    }

    /**
     * tcp 连接网关 加入重连机制
     * @param host
     * @param port
     * @return
     */
    public AioSession connect(String host, int port, Protocol protocol, MessageProcessor processor) {

        AioClient aioClient = new AioClient(host, port,protocol,processor);
        try {
            AioSession session =  aioClient.start();
            ReconnectPlugin.get().addReconnectPlugin(aioClient);
            return session;
        } catch (IOException e) {
            throw new ServerBootstrapException("网关节点连接失败, host["+host+"]  port["+port+"] " );
        }
    }

    /**
     * 写给所有网关节点
     * @param bean
     */
    public void writeAllGate(AbstractBean bean) {
        ByteBuf buf = new ByteBuf();
        bean.serialize(buf);
        gatewayList.forEach(session -> session.send(buf.array()));
    }

}
